package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;

import logic.algorithm.aco.Algorithm;
import logic.algorithm.aco.AcoMetaHeuristic;
import logic.algorithm.greedy.NearestNeighbor;
import logic.objects.Problem;

public class AcoFrame extends JFrame implements ActionListener {
	JMenuItem def;
	JMenuItem start;
	JMenuItem stop;
	JCheckBoxMenuItem as;
	JCheckBoxMenuItem eas;
	JCheckBoxMenuItem ras;
	ArrayList<JCheckBoxMenuItem> array = new ArrayList<JCheckBoxMenuItem>();
	AcoMetaHeuristic aktThread;
	Algorithm aktAlg;
	Problem problem;
	ProtocolTable table;

	public AcoFrame(Problem problem) {
		// this.setLayout(new Absolu)
		getContentPane().setBackground(new Color(255, 255, 255, 0));
		this.validate();
		this.problem = problem;
		this.setTitle("Lösen des TSP mit Hilfe verschiedener ACO Algorithmen");

		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		menuErstellen();
		// setLocationRelativeTo(null);
		setLayout(new BorderLayout());
		this.setSize(GraphicVariables.MAX_WIDTH_Frame,
				GraphicVariables.MAX_HEIGHT_Frame);
		this.setLocation(50, 50);
		
		Container cont = new Container();
		DiagrammPanel panel1 = new DiagrammPanel(problem);
		panel1.setPreferredSize(new Dimension(GraphicVariables.MAX_WIDTH_Panel,
				GraphicVariables.MAX_HEIGHT_Panel));
		panel1.setLocation(20, 20);
		this.getContentPane().add(cont, BorderLayout.CENTER);
		cont.setLayout(null);
		cont.add(panel1);
		protokollErstelle();
		this.setVisible(true);

	}

	public void reset() {
		NearestNeighbor.solve(problem);
		table.initialize();
		this.repaint();
	}

	private void menuErstellen() {
		JMenuBar menubar = new JMenuBar();
		JMenu menu = new JMenu("Start");
		JMenu algMenu = new JMenu("Algorithmus");
		JCheckBoxMenuItem item;
		for (Algorithm alg : Algorithm.values()) {
			item = alg.getItem();
			algMenu.add(item);
			item.addActionListener(this);
			array.add(item);
		}
		aktAlg = Algorithm.AntSystem;
		aktAlg.getItem().setState(true);
		def = new JMenuItem("Problem definieren...");
		menu.add(def);
		def.addActionListener(this);
		start = new JMenuItem("Algorithmus starten");
		menu.add(start);
		start.addActionListener(this);
		stop = new JMenuItem("Algorithmus stoppen");
		menu.add(stop);
		stop.addActionListener(this);

		menubar.add(menu);
		menubar.add(algMenu);

		this.setJMenuBar(menubar);
	}

	private void protokollErstelle() {
		JPanel protokolPanel = new JPanel();
		this.getContentPane().add(protokolPanel, BorderLayout.EAST);
		table = new ProtocolTable(problem);
		JScrollPane pane = new JScrollPane(table);
		pane.setPreferredSize(new Dimension(
				GraphicVariables.MAX_WIDTH_Table * 2, 400));
		protokolPanel.add(pane);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == this.def) {
			if (abortAlgToChangeProblem()) {
				SetupFrame frame = new SetupFrame(problem, this);
				frame.setVisible(true);
			}
		} else if (e.getSource() == this.start) {
			if (!algAlreadyRunning()) {
				if (aktAlg == null) {
					JOptionPane
							.showMessageDialog(
									this,
									"Bitte wählen Sie zuerst über das Menü Algorithmen einen Algorithmus aus, mit welchem das Problem berechnet werden soll.");
				} else {
					aktThread = aktAlg.getFactory().getAlgorithm(problem, this);
					aktThread.start();
				}
			}
		} else if (e.getSource() == this.stop) {
			table.add(aktAlg.getName(), aktThread.getBestTourSoFarValue());
			aktThread.setTerminated();
		} else if (e.getSource().getClass() == JCheckBoxMenuItem.class) {
			if (((JCheckBoxMenuItem) e.getSource()).getState()) {
				if (shouldAlgorithmChange()) {
					((JCheckBoxMenuItem) e.getSource()).setState(true);
					for (Algorithm alg : Algorithm.values()) {
						if (e.getSource() != alg.getItem()) {
							alg.getItem().setState(false);
						} else
							aktAlg = alg;
						new DefaultTableModel();
					}
				} else {
					((JCheckBoxMenuItem) e.getSource()).setState(false);
				}
			} else
				((JCheckBoxMenuItem) e.getSource()).setState(true);
		}
	}

	public boolean shouldAlgorithmChange() {
		if (aktThread != null && aktThread.isAlive()) {
			int n = JOptionPane
					.showConfirmDialog(
							this,
							"Wenn sie den Algorithmus ändern, wird der aktuelle Durchlauf abgebrochen. Soll fortgefahren werden?",
							"Ein Algorithmus läuft bereits",
							JOptionPane.YES_NO_OPTION);
			if (n == 0) {
				table.add(aktAlg.getName(), aktThread.getBestTourSoFarValue());
				aktThread.setTerminated();
				return true;

			} else
				return false;
		} else
			return true;
	}

	public boolean abortAlgToChangeProblem() {
		if (aktThread != null && aktThread.isAlive()) {
			int n = JOptionPane
					.showConfirmDialog(
							this,
							"Wenn Sie diese Perspektive öffnen, wird der aktuelle Durchlauf abgebrochen. Soll fortgefahren werden?",
							"Ein Algorithmus läuft noch",
							JOptionPane.YES_NO_OPTION);
			if (n == 0) {
				table.add(aktAlg.getName(), aktThread.getBestTourSoFarValue());
				aktThread.setTerminated();
				return true;

			} else
				return false;
		} else
			return true;
	}

	public boolean algAlreadyRunning() {
		if (aktThread != null && aktThread.isAlive()) {
			int n = JOptionPane
					.showConfirmDialog(
							this,
							"Der Algorithmus läuft bereits. Wollen Sie diesen nun beenden?",
							"Ein Algorithmus läuft bereits",
							JOptionPane.YES_NO_OPTION);
			if (n == 0) {
				table.add(aktAlg.getName(), aktThread.getBestTourSoFarValue());
				aktThread.setTerminated();
				JOptionPane
				.showMessageDialog(
						this,
						"Der Algorithmus wurde gestoppt. Sie können diesen nun über das Menü neu starten.");
			}
			return true;

		} else
			return false;
	}
}
